In [ ]:
import numpy as np
import pandas as pd
%matplotlib inline
import math
from xgboost.sklearn import XGBClassifier
from sklearn.cross_validation import cross_val_score
from sklearn import cross_validation
from sklearn.metrics import roc_auc_score
from matplotlib import pyplot
import seaborn
from sklearn.cross_validation import train_test_split
import xgboost as xgb
In [ ]:
train = pd.read_csv('train.csv', delimiter= "|")
test = pd.read_csv('test.csv', delimiter= "|")
target = pd.read_csv('target_train.csv', delimiter= "|")
In [ ]:
train.head()
In [ ]:
print train.columns, train.shape
In [ ]:
# общая статистика
train.describe()
In [ ]:
target.describe()
In [ ]:
test.describe()
In [ ]:
# В начале потенциально id торговой точки, пользователя и term должны оказаться лишними признаками
# Интересно увидеть сумму транзакций по топ т.точкам, пользователям и mcc кодам
In [ ]:
for column in train:
print column, ": ", len(train[column].unique())
In [ ]:
# По колву уникальных значений получаем и фактическим значениям получаем вещественные, целочисленные и категориальные признаки
real_features = ["sum", "date", "f18"]
discrete_features = ["merchant", "term_id", "user_id"]
cat_features = ["mcc", "f1", "f2", "f4","f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14","f15","f16", "f17"]
In [ ]:
# Имеем более менее равномерное распределение по кол-ву транзакций в разрезе т.точек на трейне
#(взят логарифм, чтобы сгладить пик)
print "кол-во уникальных т.точек", len(train.merchant.value_counts())
np.log(train.merchant.value_counts().head(50)).plot(kind = 'bar', figsize=(10, 5))
In [ ]:
# распределение для теста совпадает для трейна (взят логарифм, чтобы сгладить пик)
print "кол-во уникальных т.точек", len(test.merchant.value_counts())
np.log(test.merchant.value_counts().head(50)).plot(kind = 'bar', figsize=(10, 5))
In [ ]:
#Аналогично для mcc
print "кол-во уникальных т.точек", len(train.mcc.value_counts())
train.mcc.value_counts().head(50).plot(kind = 'bar', figsize=(10, 5))
In [ ]:
#Аналогично для mcc, распределения совпадают
print "кол-во уникальных mcc", len(test.mcc.value_counts())
test.mcc.value_counts().head(50).plot(kind = 'bar', figsize=(10, 5))
In [ ]:
# гистограммы можно строить сразу по нескольким признакам, за исключением пару выбросов, имеем более мене равномерное распределение
train[discrete_features].plot.hist(bins = 100, figsize=(20, 20))
test[discrete_features].plot.hist(bins = 100, figsize=(20, 20))
In [ ]:
# для категориальных признаков, кроме mcc.
# Гистограммы для теста и трейна совпадают
train[["f1", "f2", "f4","f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14","f15","f16", "f17"]].plot.hist(bins = 100, figsize=(20, 20))
test[["f1", "f2", "f4","f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14","f15","f16", "f17"]].plot.hist(bins = 100, figsize=(20, 20))
In [ ]:
train['target'] = target
In [ ]:
#Построим scatterplot для пар вещественных признаков
import seaborn
seaborn.pairplot(train[real_features+ ["target"]], hue="target", diag_kind="kde")
# по результатом видно, что таргет 1 чаще при более крупных сумме.
In [ ]:
# аналогично для категориальных признаков, для первых 10к значений
seaborn.pairplot(train[cat_features + ["target"]].head(10000), hue="target", diag_kind="kde")
# признаков много, но можно выявить интересные закономерности. Оставим для более глубого анализа
In [ ]:
# аналогично для дискретных признаков, для первых 10к значений
seaborn.pairplot(train[discrete_features + ["target"]].head(10000), hue="target", diag_kind="kde")
# эти три признака на первый взгляд не влияют на отклик, генерацию признаков отложим до первого безлайна
In [ ]:
# построим матрицу корреляций не категориальных признаков
seaborn.heatmap(train[discrete_features+real_features].corr(), square=True)
#значимой коррелации, кроме как т.точки и term_id (договор)
In [ ]:
train.date.head(5)
In [ ]:
# поиграемсяс датой, добавим день месяц и тд
train = pd.read_csv('train.csv', delimiter= "|")
test = pd.read_csv('test.csv', delimiter= "|")
target = pd.read_csv('target_train.csv', delimiter= "|")
def fix_date_time(df):
def extract_field(_df, start, stop):
return _df['date'].map(lambda dt: int(dt[start:stop]))
df['Year'] = extract_field(df,0,4)
df['Month'] = extract_field(df,5,7)
df['Day'] = extract_field(df,8,10)
df['Hour'] = extract_field(df,11,13)
df['Minute'] = extract_field(df,14,16)
return df.drop(['date'], axis = 1)
train = fix_date_time(train)
test = fix_date_time(test)
In [ ]:
print train.Year.unique(), test.Year.unique()
# диапозоны дат у данных пересекающиеся, так что
In [ ]:
from sklearn.cross_validation import train_test_split
X_fit, X_eval, y_fit, y_eval= train_test_split(
train, target, test_size=0.20, random_state=1
)
In [ ]:
#обучим первую модель. Логистическую регрессию, поварьируем регуляризацию
from sklearn.linear_model import LogisticRegression
from sklearn import cross_validation
from sklearn.metrics import roc_auc_score
from sklearn import grid_search
lr = LogisticRegression()
CVscores = cross_validation.cross_val_score(lr, X_fit, y_fit.target, scoring='roc_auc', cv=5)
#поварьируем регуляризацию
Cs = 10**np.linspace(-4, 4, num=10)
grid = {'C': Cs}
gridsearch = grid_search.GridSearchCV(lr, grid, scoring='roc_auc', cv=5)
gridsearch.fit(X_fit, y_fit.target)
gridscores = [-x.mean_validation_score for x in gridsearch.grid_scores_]
C = Cs[np.argmin(gridscores)]
# обучим модель с полученными параметрами
lrCV = LogisticRegression(C=C)
lrCV.fit(X_fit, y_fit)
In [ ]:
auc_train = roc_auc_score(y_fit.target, lrCV.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, lrCV.predict(X_eval))
print 'auc_train: ', auc_train
print 'auc_val: ', auc_val
In [ ]:
# результаты получиcь достаточно плохие, если в таргете среднее значение результатов 0,47, то тут 0,06 - модель сильно переобучилась в сторону 0
print np.mean(lrCV.predict(X_fit)), target.mean(), np.mean(y_fit.target)
In [ ]:
#Применим xgboost, он должен показать хорошие первоначальные результаты за счет того что
# отлично борется c переобучением
# Разделим данные на обучающую, валидационную и тестовую выборку. Данные достаточно много, это имеет смысл сделать
import xgboost as xgb
clf = xgb.XGBClassifier(missing=np.nan, max_depth=3,
n_estimators=750, learning_rate=0.01, gamma =0.3, min_child_weight = 3,
subsample=0.9, colsample_bytree=0.8, seed=2000,objective= 'binary:logistic')
clf.fit(X_fit, y_fit, early_stopping_rounds=40, eval_metric="auc", eval_set=[(X_eval, y_eval)])
In [ ]:
auc_train = roc_auc_score(y_fit.target, clf.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, clf.predict(X_eval))
print 'auc_train: ', auc_train
print 'auc_val: ', auc_val
In [ ]:
print np.mean(clf.predict(X_fit)), target.mean(), np.mean(y_fit.target)
# значения стало лучше AUC чуть меньше 0,6
In [ ]:
# расмотрим какие признаки модель посчитала важными
def get_xgb_imp(xgb, feat_names):
from numpy import array
imp_vals = xgb.booster().get_fscore()
imp_dict = {feat_names[i]:float(imp_vals.get('f'+str(i),0.)) for i in range(len(feat_names))}
total = array(imp_dict.values()).sum()
return {k:v/total for k,v in imp_dict.items()}
get_xgb_imp(clf,X_fit.columns)
In [ ]:
# необычно, юзер id - оказался сильно значимым признаком.
# огорчает, что неизвестно на момент решения задачи что именно классиф.
train = train.drop(['f14', 'f15'],axis=1)
test = test.drop(['f14', 'f15'],axis=1)
In [ ]:
# добавим частоту транзакций к mcc коду
mcc_con = pd.concat([test['mcc'], train['mcc']])
values = dict(mcc_con.value_counts())
train['_mcc_freq'] = train['mcc'].map(values)
test['_mcc_freq'] = test['mcc'].map(values)
train['_mcc_freq'] = train['_mcc_freq'].fillna(-1)
test['_mcc_freq'] = test['_mcc_freq'].fillna(-1)
print train.head()
print(train.info())
In [ ]:
# обучим модель еще раз
X_fit, X_eval, y_fit, y_eval= train_test_split(
train, target, test_size=0.20, random_state=1
)
clf = xgb.XGBClassifier(missing=np.nan, max_depth=3,
n_estimators=750, learning_rate=0.01, gamma =0.3, min_child_weight = 3,
subsample=0.9, colsample_bytree=0.8, seed=2000,objective= 'binary:logistic')
clf.fit(X_fit, y_fit, early_stopping_rounds=40, eval_metric="auc", eval_set=[(X_eval, y_eval)])
auc_train = roc_auc_score(y_fit.target, clf.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, clf.predict(X_eval))
print 'auc_train: ', auc_train
print 'auc_val: ', auc_val
In [ ]:
# результаты несколько улучшились
get_xgb_imp(clf,X_fit.columns)
In [ ]:
# новый признак не привнес нового в модель, дропнем его, но попробуем заменить частотами три айдишника, кроме mcc
# при этом сами id дропнуть
term_con = pd.concat([test['term_id'], train['term_id']])
values = dict(term_con.value_counts())
train['_term_freq'] = train['term_id'].map(values)
test['_term_freq'] = test['term_id'].map(values)
mer_con = pd.concat([test['merchant'], train['merchant']])
values = dict(mer_con.value_counts())
train['_merchant_freq'] = train['merchant'].map(values)
test['_merchant_freq'] = test['merchant'].map(values)
user_con = pd.concat([test['user_id'], train['user_id']])
values = dict(mer_con.value_counts())
train['_user_freq'] = train['merchant'].map(values)
test['_user_freq'] = test['merchant'].map(values)
#дропнем так же незначимые признаки
train = train.drop(['Minute', 'Year', 'f11', 'f12', 'f13', 'f16', 'f17', 'f7', 'f8'],axis=1)
test = test.drop(['Minute', 'Year', 'f11', 'f12', 'f13', 'f16', 'f17', 'f7', 'f8'],axis=1)
train = train.drop(['merchant', 'user_id', 'term_id'],axis=1)
test = test.drop(['merchant', 'term_id', 'user_id'],axis=1)
In [ ]:
X_fit, X_eval, y_fit, y_eval= train_test_split(
train, target, test_size=0.20, random_state=1
)
clf = xgb.XGBClassifier(missing=np.nan, max_depth=3,
n_estimators=1300, learning_rate=0.02, gamma =0.3, min_child_weight = 3,
subsample=0.9, colsample_bytree=0.8, seed=2000,objective= 'binary:logistic')
clf.fit(X_fit, y_fit, early_stopping_rounds=50, eval_metric="auc", eval_set=[(X_eval, y_eval)])
auc_train = roc_auc_score(y_fit.target, clf.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, clf.predict(X_eval))
print 'auc_train: ', auc_train
print 'auc_val: ', auc_val
In [ ]:
test_target = clf.predict(test)
submission = pd.DataFrame(test_target)
submission.to_csv("test_target.csv", index=False)
In [ ]: